﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Media3D;

namespace TimeSolve
{
    public class ViewControler
    {
        public ViewControler(CoordinateSystem coordinate)
        {
            this.coordinate = coordinate;
        }
        public CoordinateSystem coordinate { get; set; }
        public void linkViewport(Viewport3D viewport3D,DirectionalLight cameraLight,Point3D graphCenter,double graphRadius)
        {
            this.viewport3D  = viewport3D;
            this.cameraLight  = cameraLight;
            this.ocamera = viewport3D.Camera as OrthographicCamera;
            this.pcamera = viewport3D.Camera as PerspectiveCamera;
            this.graphCenter  = graphCenter;
            this.rotateCenter = graphCenter;
            this.graphRadiusEx = graphRadius*2;
            //矢量归一 
            if(ocamera != null)
            {
                ocamera.LookDirection.Normalize();
                ocamera.UpDirection = VectorCal.VectorToPlane(ocamera.UpDirection, ocamera.LookDirection);//方向校准
                ocamera.UpDirection.Normalize();
                cameraToBoundNormO();
                coordinate.ViewFollow(ocamera);
                lightFollowO(ocamera);
            }else
            {

            }
        }
        public OrthographicCamera ocamera { get; set; }
        public PerspectiveCamera pcamera { get; set; }
        public Viewport3D viewport3D { get; set; }
        public Point3D graphCenter { get; set; }  
        public double graphRadiusEx { get; set; }
        public Point3D rotateCenter { get; set; }
        public DirectionalLight cameraLight { get; set; }
        public void lightFollowO(OrthographicCamera  camera)
        {
            if (cameraLight == null) return;
            cameraLight.Direction = camera.LookDirection - 0.2 * camera.UpDirection;              
        }
        public void rotate(double verticalRate, double horizontalRate)
        {
            verticalRate *= 270;
            horizontalRate *= 270;
            if(ocamera != null)
            {
                Vector3D vright = Vector3D.CrossProduct(ocamera.LookDirection, ocamera.UpDirection);
                Vector3D axis = -verticalRate * vright - horizontalRate * ocamera .UpDirection;
                if (axis.Length == 0)
                {
                    return;
                }             
                Quaternion q = new Quaternion(axis, axis.Length);              
                Matrix3D m3 = new Matrix3D();
                m3.RotateAt(q, rotateCenter);
                ocamera.Position = m3.Transform(ocamera.Position);
                ocamera.UpDirection = m3.Transform(ocamera.UpDirection);
                ocamera.LookDirection = m3.Transform(ocamera.LookDirection);
                cameraToBoundNormO();
                coordinate.ViewFollow(ocamera);
                lightFollowO(ocamera);
            }

        }
        private void cameraToBoundNormO()//camera不能超过边界
        {
            Vector3D originToCamera = ocamera.Position - graphCenter;
            double dmin = Vector3D.DotProduct(originToCamera, ocamera.LookDirection);//距离
            double Dpow2 = originToCamera.LengthSquared - Math.Pow(dmin, 2); //圆心到弦的距离
            double banXianChang = Math.Sqrt(Math.Pow(graphRadiusEx, 2) - Dpow2);//半弦长
            double t = -dmin - banXianChang;
            ocamera.Position += t * ocamera.LookDirection;
            ocamera.LookDirection.Normalize();
            ocamera.UpDirection.Normalize();
        }
        public void move(double verticalRate, double horizontalRate)
        {
            if(ocamera != null)
            {
                Vector3D vright = Vector3D.CrossProduct(ocamera.LookDirection, ocamera.UpDirection);
                Vector3D move = verticalRate * ocamera.Width * ocamera.UpDirection - horizontalRate * ocamera.Width * vright;//camera位置与物体移动方向相反
                ocamera.Position = ocamera.Position + move;
                cameraToBoundNormO();
            }

        }
        public void zoom(double xi, double relativeToZoonCenter_x, double relativeToZoomCenter_y)//verticalCenter用vertical的数值
        {
            if(ocamera != null)            
            {  
                Vector3D vright = Vector3D.CrossProduct(ocamera.LookDirection, ocamera.UpDirection);   
                Vector3D cameraToZoomcenter = relativeToZoomCenter_y *ocamera .Width * ocamera.UpDirection + relativeToZoonCenter_x*ocamera.Width * vright;
                Point3D fixp = ocamera.Position + cameraToZoomcenter;
                ocamera.Width /= xi;
                cameraToZoomcenter /=  xi;
                ocamera.Position = fixp - cameraToZoomcenter;
                cameraToBoundNormO();
            }

        }
        public void fit()
        {
            Rect bounds = VisualTreeHelper.GetDescendantBounds(this.viewport3D);
            double xmove = this.viewport3D .ActualWidth / 2 - (bounds.X + bounds.Width / 2);
            double ymove = this.viewport3D .ActualHeight / 2 - (bounds.Y + bounds.Height / 2);

            move(ymove / this.viewport3D.ActualWidth, xmove / this.viewport3D.ActualWidth);
            double xs = bounds.Width / this.viewport3D.ActualWidth;
            double ys = bounds.Height / this.viewport3D.ActualHeight;
            ocamera.Width *= 1.2 * Math.Max(xs, ys);
        }

        public void setView(Vector3D upDirection, Vector3D lookDirection)
        {
            if(ocamera != null)
            {
                Point3D viewcenter = VectorCal.PointToPlane(ocamera.Position, ocamera.LookDirection, graphCenter);
                Point3D newviewcenter = VectorCal.PointToPlane(ocamera.Position, lookDirection, graphCenter);
                ocamera.Position +=  viewcenter-newviewcenter;
                ocamera.UpDirection = upDirection;
                ocamera.LookDirection = lookDirection;
                cameraToBoundNormO();
                coordinate.ViewFollow(ocamera);
                lightFollowO(ocamera);
            }
      
        }

    }
}
